package upload

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"gitee.com/bobo-rs/creative-framework/pkg/config"
	"gitee.com/bobo-rs/creative-framework/pkg/utils"
	"gitee.com/bobo-rs/creative-services/framework/model"
	"gitee.com/bobo-rs/creative-services/framework/model/entity"
	"gitee.com/bobo-rs/creative-services/framework/service"
	"github.com/gogf/gf/v2/crypto/gmd5"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/os/gfile"
	"io"
	"strings"
)

type sUpload struct {
}

var (
	RawConfig = &config.UploadConfigItem{}
)

func init() {
	// 初始化接口
	service.RegisterUpload(New())
}

func New() *sUpload {
	return &sUpload{}
}

// FileUpload 文件上传
func (u *sUpload) FileUpload(ctx context.Context, in model.UploadFileInput) (out *model.UploadFileOutput, err error) {
	out = &model.UploadFileOutput{}
	// 读取配置
	RawConfig, err = u.GetConfig(ctx)
	if err != nil {
		return nil, err
	}

	// 验证扩展
	ets := strings.Split(RawConfig.UploadExt, ",")
	if len(ets) == 0 || utils.NewArray(ets).MustIsExists(gfile.ExtName(in.File.Filename)) == false {
		return nil, gerror.New(`上传文件格式错误`)
	}

	// 获取附件信息
	hasher, attachId, err := u.processFileHasherAndAttachId(in.File)
	if err != nil {
		return nil, nil
	}

	resp := &model.UploadAttachmentItem{
		Hasher:   hasher,
		AttachId: attachId,
	}
	// 获取附件信息避免重复上传
	err = service.Attachment().ProcessAttachmentDetailByHasher(ctx, hasher, &resp)
	if err == nil {
		out.UploadAttachmentItem = *resp
		return
	}

	// 上传详情
	in.Name = attachId
	switch RawConfig.StorageType {
	case `local`:
		err = u.ProcessLocalUpload(ctx, in, resp)
	default:
		return nil, gerror.New(`上传通道未开通` + RawConfig.StorageType)
	}
	if err != nil {
		return nil, err
	}

	// 保存上传附件
	_, err = service.Attachment().SaveAttachment(ctx, entity.Attachment{
		AttPath:     resp.AttPath,
		AttUrl:      resp.AttUrl,
		AttSize:     resp.AttSize,
		AttType:     resp.AttType,
		StorageType: resp.StorageType,
		RealName:    resp.RealName,
		Name:        resp.Name,
		AttachId:    attachId,
		Hasher:      hasher,
		Width:       resp.Width,
		Height:      resp.Height,
	})
	if err != nil {
		return nil, gerror.Wrapf(err, `保存上传文件报错%s`, err.Error())
	}
	out.UploadAttachmentItem = *resp
	return
}

// processFileHasherAndAttachId 处理文件hash值和附件ID
func (u *sUpload) processFileHasherAndAttachId(file *ghttp.UploadFile) (hasher, attachId string, err error) {
	fs, err := file.Open()
	if err != nil {
		return "", "", err
	}
	defer func() {
		_ = fs.Close()
	}()

	// 创建一个Hash值
	hash := sha256.New()

	if _, err = io.Copy(hash, fs); err != nil {
		return "", "", gerror.Wrapf(err, `复制文件内容到Hasher失败%s`, err.Error())
	}

	// 转换为字符串
	hasher = hex.EncodeToString(hash.Sum(nil))

	// attachId附件ID
	attachId = gmd5.MustEncryptString(hasher)
	return
}

// GetConfig 读取文件上传配置
func (u *sUpload) GetConfig(ctx context.Context) (rawConfig *config.UploadConfigItem, err error) {
	return config.New().GetUploadsConfig(ctx)
}
